﻿using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity;
using UnityEngine;
using UnityEngine.Networking;

[RequireComponent(typeof(Rigidbody))]
public class Move : CharacterBehaviour
{
    [Tooltip("Handled parameter: \nvelocityX(float)\nvelocityZ(float)\nisMoving(bool)")]
    public Animator anim;
    public Vector3 direction;
    private Coroutine forceMoveTo;
    private int hash_isMoving = Animator.StringToHash("isMoving");
    private int hash_velocityX = Animator.StringToHash("velocityX");
    private int hash_velocityZ = Animator.StringToHash("velocityZ");
    private float initialSpeed;
    private Inventory inventory;
    private static int kCmdCmdSetDirection = -1762428914;
    private static int kCmdCmdSetPosition;
    private Vector3 lastDir;
    private Vector3 lastPos;
    private float lastSendPosTime;
    private Coroutine powerup;
    private Rigidbody rb;
    public float speed = 5f;
    [SyncVar]
    private NetworkDirection syncDirection;
    [SyncVar]
    private NetworkPosition syncPosition;

    static Move()
    {
        NetworkBehaviour.RegisterCommandDelegate(typeof(Move), kCmdCmdSetDirection, new NetworkBehaviour.CmdDelegate(Move.InvokeCmdCmdSetDirection));
        kCmdCmdSetPosition = 0x64d75aba;
        NetworkBehaviour.RegisterCommandDelegate(typeof(Move), kCmdCmdSetPosition, new NetworkBehaviour.CmdDelegate(Move.InvokeCmdCmdSetPosition));
        NetworkCRC.RegisterBehaviour("Move", 0);
    }

    public void ApplyImpact(Vector3 vector)
    {
        vector.y = 0f;
        this.ForceMoveTo(this.rb.position + vector, 0.1f, null);
    }

    protected override void Awake()
    {
        base.Awake();
        this.rb = base.GetComponent<Rigidbody>();
        this.trailGhost = base.gameObject.GetOrAddComponent<TrailGhost>();
        this.inventory = base.GetComponent<Inventory>();
    }

    public void CallCmdSetDirection(NetworkDirection value)
    {
        if (!NetworkClient.active)
        {
            Debug.LogError("Command function CmdSetDirection called on server.");
        }
        else if (base.isServer)
        {
            this.CmdSetDirection(value);
        }
        else
        {
            NetworkWriter writer = new NetworkWriter();
            writer.Write((short) 0);
            writer.Write((short) ((ushort) 5));
            writer.WritePackedUInt32((uint) kCmdCmdSetDirection);
            writer.Write(base.GetComponent<NetworkIdentity>().netId);
            GeneratedNetworkCode._WriteNetworkDirection_None(writer, value);
            base.SendCommandInternal(writer, 0, "CmdSetDirection");
        }
    }

    public void CallCmdSetPosition(NetworkPosition value)
    {
        if (!NetworkClient.active)
        {
            Debug.LogError("Command function CmdSetPosition called on server.");
        }
        else if (base.isServer)
        {
            this.CmdSetPosition(value);
        }
        else
        {
            NetworkWriter writer = new NetworkWriter();
            writer.Write((short) 0);
            writer.Write((short) ((ushort) 5));
            writer.WritePackedUInt32((uint) kCmdCmdSetPosition);
            writer.Write(base.GetComponent<NetworkIdentity>().netId);
            GeneratedNetworkCode._WriteNetworkPosition_None(writer, value);
            base.SendCommandInternal(writer, 0, "CmdSetPosition");
        }
    }

    [Command]
    private void CmdSetDirection(NetworkDirection value)
    {
        this.NetworksyncDirection = value;
    }

    [Command]
    private void CmdSetPosition(NetworkPosition value)
    {
        this.NetworksyncPosition = value;
    }

    private bool Equals(Vector3 a, Vector3 b)
    {
        return (Vector3.Distance(a, b) < 0.01f);
    }

    public Coroutine ForceMoveTo(Vector3 destPos, float duration, AnimationCurve curve = null)
    {
        if (curve == null)
        {
            curve = AnimationCurve.Linear(0f, 0f, 1f, 1f);
        }
        if (this.forceMoveTo != null)
        {
            base.StopCoroutine(this.forceMoveTo);
        }
        this.forceMoveTo = this.StartAnimateVector3(this.rb.position, destPos, duration, curve, delegate (Vector3 pos) {
            Vector3 vector = pos - this.rb.position;
            this.rb.velocity = (Vector3) (vector * 10f);
        }, delegate {
            this.forceMoveTo = null;
        });
        return this.forceMoveTo;
    }

    protected static void InvokeCmdCmdSetDirection(NetworkBehaviour obj, NetworkReader reader)
    {
        if (!NetworkServer.active)
        {
            Debug.LogError("Command CmdSetDirection called on client.");
        }
        else
        {
            ((Move) obj).CmdSetDirection(GeneratedNetworkCode._ReadNetworkDirection_None(reader));
        }
    }

    protected static void InvokeCmdCmdSetPosition(NetworkBehaviour obj, NetworkReader reader)
    {
        if (!NetworkServer.active)
        {
            Debug.LogError("Command CmdSetPosition called on client.");
        }
        else
        {
            ((Move) obj).CmdSetPosition(GeneratedNetworkCode._ReadNetworkPosition_None(reader));
        }
    }

    public override void OnDeserialize(NetworkReader reader, bool initialState)
    {
        base.OnDeserialize(reader, initialState);
        if (initialState)
        {
            this.syncDirection = GeneratedNetworkCode._ReadNetworkDirection_None(reader);
            this.syncPosition = GeneratedNetworkCode._ReadNetworkPosition_None(reader);
        }
        else
        {
            int num = (int) reader.ReadPackedUInt32();
            if ((num & 1) != 0)
            {
                this.syncDirection = GeneratedNetworkCode._ReadNetworkDirection_None(reader);
            }
            if ((num & 2) != 0)
            {
                this.syncPosition = GeneratedNetworkCode._ReadNetworkPosition_None(reader);
            }
        }
    }

    protected virtual void OnEnable()
    {
        this.forceMoveTo = null;
        if (this.trailGhost != null)
        {
            this.trailGhost.enabled = false;
        }
    }

    public override bool OnSerialize(NetworkWriter writer, bool forceAll)
    {
        bool flag2 = base.OnSerialize(writer, forceAll);
        if (forceAll)
        {
            GeneratedNetworkCode._WriteNetworkDirection_None(writer, this.syncDirection);
            GeneratedNetworkCode._WriteNetworkPosition_None(writer, this.syncPosition);
            return true;
        }
        bool flag = false;
        if ((base.syncVarDirtyBits & 1) != 0)
        {
            if (!flag)
            {
                writer.WritePackedUInt32(base.syncVarDirtyBits);
                flag = true;
            }
            GeneratedNetworkCode._WriteNetworkDirection_None(writer, this.syncDirection);
        }
        if ((base.syncVarDirtyBits & 2) != 0)
        {
            if (!flag)
            {
                writer.WritePackedUInt32(base.syncVarDirtyBits);
                flag = true;
            }
            GeneratedNetworkCode._WriteNetworkPosition_None(writer, this.syncPosition);
        }
        if (!flag)
        {
            writer.WritePackedUInt32(base.syncVarDirtyBits);
        }
        return (flag | flag2);
    }

    public void Powerup(float duration, float multiplier = 1.5f)
    {
        this.trailGhost = this.rb.gameObject.GetOrAddComponent<TrailGhost>();
        this.speed = this.initialSpeed * multiplier;
        this.powerup.Stop(this);
        this.powerup = this.StartWaitForSeconds(duration, delegate {
            this.speed = this.initialSpeed;
            if (this.trailGhost != null)
            {
                this.trailGhost.enabled = false;
            }
        });
        this.trailGhost.enabled = true;
    }

    protected virtual void Start()
    {
        this.initialSpeed = this.speed;
        if (this.anim == null)
        {
            this.anim = base.GetComponentInChildren<Animator>();
        }
    }

    public void StopMoving()
    {
        this.rb.velocity = Vector3.zero;
    }

    private void UNetVersion()
    {
    }

    protected virtual void Update()
    {
        if (!this.isForceMoving)
        {
            float speed = this.speed;
            if (this.inventory != null)
            {
                speed = Mathf.Max((float) (this.speed - this.inventory.weight), (float) 1f);
            }
            Vector3 vector = (Vector3) (this.direction.normalized * speed);
            this.rb.velocity = this.rb.velocity.SetXZ(vector.x, vector.z);
            this.rb.drag = (this.rb.velocity.y <= 1f) ? ((float) 0) : ((float) 50);
            this.UpdateNetwork();
            this.UpdateAnimations();
        }
    }

    private void UpdateAnimations()
    {
        if ((this.anim != null) && this.anim.isInitialized)
        {
            if (this.anim.HasParameter(this.hash_velocityX))
            {
                this.anim.SetFloat(this.hash_velocityX, this.localVelocity.x);
            }
            if (this.anim.HasParameter(this.hash_velocityZ))
            {
                this.anim.SetFloat(this.hash_velocityZ, this.localVelocity.z);
            }
            if (this.anim.HasParameter(this.hash_isMoving))
            {
                this.anim.SetBool(this.hash_isMoving, this.rb.velocity.magnitude.Abs() > 0.1f);
            }
        }
    }

    private void UpdateNetwork()
    {
        if (NetworkUtility.isNetworkActive)
        {
            float num = 0.5f;
            float num2 = 1f;
            if (base.hasAuthority)
            {
                this.direction = this.direction.normalized.Snap((float) 1f);
                if (((this.direction == Vector3.zero) || (this.lastDir != this.direction)) && ((Vector3.Distance(this.lastPos, base.transform.position) > num) || (((Time.time - this.lastSendPosTime) > num2) && !this.Equals(this.lastPos, base.transform.position))))
                {
                    Debug.DrawRay(base.transform.position, Vector3.up, Color.yellow, 0.3f);
                    this.CallCmdSetPosition(base.transform.position);
                    this.lastPos = base.transform.position;
                    this.lastSendPosTime = Time.time;
                }
                if (this.lastDir != this.direction)
                {
                    Debug.DrawRay(base.transform.position, this.direction, Color.blue, 0.3f);
                    this.CallCmdSetDirection(this.direction);
                    this.lastDir = this.direction;
                }
            }
            else
            {
                this.direction = (Vector3) this.syncDirection;
                if (this.direction == Vector3.zero)
                {
                    if (Vector3.Distance(base.transform.position, (Vector3) this.syncPosition) > 5f)
                    {
                        base.transform.position = (Vector3) this.syncPosition;
                    }
                    base.transform.position = Vector3.Lerp(base.transform.position, (Vector3) this.syncPosition, Time.deltaTime * 10f);
                }
            }
        }
    }

    public bool isForceMoving
    {
        get
        {
            return (this.forceMoveTo != null);
        }
    }

    private Vector3 localVelocity
    {
        get
        {
            return base.transform.InverseTransformDirection(this.rb.velocity);
        }
    }

    public NetworkDirection NetworksyncDirection
    {
        get
        {
            return this.syncDirection;
        }
        [param: In]
        set
        {
            base.SetSyncVar<NetworkDirection>(value, ref this.syncDirection, 1);
        }
    }

    public NetworkPosition NetworksyncPosition
    {
        get
        {
            return this.syncPosition;
        }
        [param: In]
        set
        {
            base.SetSyncVar<NetworkPosition>(value, ref this.syncPosition, 2);
        }
    }

    public TrailGhost trailGhost { get; private set; }
}

